package org.wisdom.service;

import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.mvc.condition.RequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.util.pattern.PathPatternParser;
import org.wisdom.annotation.AppFacade;
import org.wisdom.annotation.WisdomController;

import lombok.extern.slf4j.Slf4j;

/**
 * 处理服务API请求路径和FeignClient路径一致
 *
 * @author 张智研
 * @date 2022/05/29 11:33
 **/
@SuppressWarnings("NullableProblems")
@Slf4j
public class WisdomRequestMappingHandlerMapping extends RequestMappingHandlerMapping {

    @Override
    protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
        WisdomController wisdomController = handlerType.getAnnotation(WisdomController.class);
        RequestMappingInfo info = super.getMappingForMethod(method, handlerType);
        AppFacadeInfo appFacadeInfo = null;
        if (wisdomController == null) {
            return info;
        }
        Class<?>[] interfaces = handlerType.getInterfaces();
        if (interfaces.length > 0) {
            for (Class<?> interF : interfaces) {
                appFacadeInfo = this.createAcRequestMappingInfo(interF);
                if (appFacadeInfo != null) {
                    RequestMappingInfo baseInfo = appFacadeInfo.getRequestMappingInfo();
                    info = this.createDefaultRequestMappingInfo(method);
                    if (info != null) {
                        info = baseInfo.combine(info);
                        break;
                    }
                }
            }
        }
        if(info == null) {
            return null;
        }
        if(appFacadeInfo == null) {
            appFacadeInfo = new AppFacadeInfo();
        }
        AppFacade appFacade = AnnotatedElementUtils.findMergedAnnotation(method, AppFacade.class);
        if(appFacade != null && StringUtils.hasLength(appFacade.value())) {
            appFacadeInfo.setTitle(appFacade.value());
        }
        PreAuthorize preAuthorize = AnnotatedElementUtils.findMergedAnnotation(method, PreAuthorize.class);
        if(preAuthorize != null && StringUtils.hasLength(preAuthorize.value())) {
            String permission = preAuthorize.value();
            permission = permission.replaceAll("@ps.hasPermission|\\(|\\)|'|\"","");
            appFacadeInfo.setPermission(permission);
        }
        appFacadeInfo.setRequestMappingInfo(info);
        // 注册服务到注册表
        WisdomRegistry.APP_INFOS.add(appFacadeInfo);
        return info;
    }

    /**
     * 创建通用request服务路径
     *
     * @author 张智研
     * @date 2022/05/29 15:53
     * @param element
     *            RequestMapping注解
     * @return org.springframework.web.servlet.mvc.method.RequestMappingInfo
     */
    private RequestMappingInfo createDefaultRequestMappingInfo(AnnotatedElement element) {
        RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
        RequestCondition<?> condition = (element instanceof Class ? getCustomTypeCondition((Class<?>)element)
            : getCustomMethodCondition((Method)element));
        return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
    }

    /**
     * 创建acRequest服务路径
     *
     * @author 张智研
     * @date 2022/05/29 15:53
     * @param element
     *            FeignClient注解
     * @return org.springframework.web.servlet.mvc.method.RequestMappingInfo
     */
    private AppFacadeInfo createAcRequestMappingInfo(AnnotatedElement element) {
        FeignClient feignClient = AnnotatedElementUtils.findMergedAnnotation(element, FeignClient.class);
        RequestCondition<?> condition = (element instanceof Class ? getCustomTypeCondition((Class<?>)element)
            : getCustomMethodCondition((Method)element));
        return (feignClient != null ? createAcRequestMappingInfo(feignClient, condition) : null);
    }

    /**
     * 创建接口服务API路径信息
     *
     * @author 张智研
     * @date 2022/05/29 14:59
     * @param annotation
     *            FeignClient注解
     * @param customCondition
     *            自定义条件
     * @return org.springframework.web.servlet.mvc.method.RequestMappingInfo
     */
    private AppFacadeInfo createAcRequestMappingInfo(FeignClient annotation, RequestCondition<?> customCondition) {
        String path = annotation.path();
        String[] patterns = new String[1];
        patterns[0] = path;
        RequestMappingInfo.Builder builder = RequestMappingInfo.paths(resolveEmbeddedValuesInPatterns(patterns));
        if (customCondition != null) {
            builder.customCondition(customCondition);
        }
        RequestMappingInfo.BuilderConfiguration configuration = new RequestMappingInfo.BuilderConfiguration();
        configuration.setPatternParser(new PathPatternParser());

        AppFacadeInfo acAppFacadeInfo = new AppFacadeInfo();
        acAppFacadeInfo.setRequestMappingInfo(builder.options(configuration).build());
        String[] names = new String[1];
        names[0] = annotation.name();
        acAppFacadeInfo.setName(resolveEmbeddedValuesInPatterns(names)[0]);
        return acAppFacadeInfo;
    }

}
